package cn.com.cis.web.actions;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap;

import cn.com.cis.domain.JobConfig;
import cn.com.cis.domain.JobLog;
import cn.com.cis.domain.User;
import cn.com.cis.domain.XmlJob;
import cn.com.cis.plugins.mybatis.PageInfo;
import cn.com.cis.service.ETLExecutorService;
import cn.com.cis.service.JobConfigService;
import cn.com.cis.service.JobLogService;
import cn.com.cis.service.QrtzJobService;
import cn.com.cis.service.UserService;
import cn.com.cis.service.XmlJobService;

@Controller
@RequestMapping(value = "/cronJob")
public class CronJobController {
	
	@Autowired
	private JobConfigService jobConfigService;
	
	@Autowired
	private QrtzJobService qrtzService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private JobLogService jobLogService;
	
	@Autowired
	private XmlJobService xmlJobService;
	
	private void setNavigateBar(ModelAndView mv){
    	mv.addObject("icon", "icon-list");
        mv.addObject("title", "计划任务");
    }

	@RequiresPermissions("计划任务:查看计划任务列表")
    @RequestMapping(value = "/list",method = RequestMethod.GET)
    public ModelAndView list(@RequestParam(value = "page", defaultValue = "1", required = false) int page,
                             @RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize, HttpServletRequest request) throws SchedulerException {
        ModelAndView mv = new ModelAndView("cronJob/list");
        setNavigateBar(mv);
        
        List<JobConfig> scheduleJobs = jobConfigService.queryAllJobs(page, pageSize);
        PageInfo<JobConfig> pageInfo = new PageInfo<JobConfig>(scheduleJobs, pageSize);
        
        List<User> users = userService.selectAllUser();
        Map<Integer, String> idNameMap = new HashMap<Integer, String>();
        for(User user : users){
        	idNameMap.put(user.getId(), user.getUsername());
        }
        mv.addObject("idNameMap", idNameMap);
        
        List<XmlJob> jobs = xmlJobService.selectJobs();
        mv.addObject("jobs", jobs);
        
        mv.addObject("page",page);
        mv.addObject("scheduleJobs", scheduleJobs);
        mv.addObject("pageInfo", pageInfo);
        
        mv.addObject("error", request.getParameter("error"));
        mv.addObject("msg", request.getParameter("msg"));
        
        return mv;
    }
	
	@RequiresPermissions("计划任务:添加计划任务")
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addView() {
        ModelAndView mav = new ModelAndView("/cronJob/add");
        setNavigateBar(mav);
        
        List<XmlJob> jobs = xmlJobService.selectJobs();
        mav.addObject("jobs", jobs);
        
        return mav;
    }
    
	@RequiresPermissions("计划任务:添加计划任务")
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    // TODO should be in one transaction
	public String addJob(String jobNameDisplay, String cronExpression, Integer etlXmlId, Boolean enable, String des, HttpServletRequest httpServletRequest) {
		HttpSession session = httpServletRequest.getSession();
        User currentUser = (User)session.getAttribute("user");
		
    	JobConfig jobConfig = new JobConfig();
    	jobConfig.setJobNameDisplay(jobNameDisplay);
    	jobConfig.setCronExpression(cronExpression);
    	jobConfig.setEtlXmlId(etlXmlId);
    	jobConfig.setEnable(enable);
    	jobConfig.setDes(des);
    	jobConfig.setSetupUserId(currentUser.getId());
    	
    	jobConfigService.insertJobConfig(jobConfig);
    	
		try {
			if (enable) {
				qrtzService.immediateExecutorJob(jobConfig);
			}
		} catch (Exception e) {
			e.printStackTrace();
			jobConfig.setEnable(false);
			jobConfigService.updateJobConfig(jobConfig);
			return e.getMessage();
		}
		
		return "success";
	}
    
	@RequiresPermissions("计划任务:启停计划任务")
    @RequestMapping(value = "/startJob", method = RequestMethod.POST)
    @ResponseBody
	public String startJob(int jobId, int enable, HttpServletRequest httpServletRequest) {
    	
    	JobConfig jobConfig = jobConfigService.queryJobConfigById(jobId);
    	
    	HttpSession session = httpServletRequest.getSession();
        User currentUser = (User)session.getAttribute("user");
        jobConfig.setSetupUserId(currentUser.getId());
    	
		try {
			if (enable == 1) {
				jobConfig.setEnable(true);
				qrtzService.makeJobScheduled(jobConfig);
			} else {
				jobConfig.setEnable(false);
				qrtzService.unscheduleJob(jobConfig);
			}
			jobConfigService.updateJobConfig(jobConfig);
		} catch (Exception exception) {
			exception.printStackTrace();
			return exception.getMessage();
		}
    	
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		return "success" + sdf.format(jobConfig.getNextExecuteTime());
	}
    
	@RequiresPermissions("计划任务:删除计划任务")
    @RequestMapping(value = "/deleteJob", method = RequestMethod.GET)
	public ModelAndView deleteJob(int jobId, int page, RedirectAttributesModelMap modelMap) throws UnsupportedEncodingException {
    	
    	ModelAndView mv = new ModelAndView("redirect:/cronJob/list?page=" + page);
    	setNavigateBar(mv);
    	
    	JobConfig jobConfig = jobConfigService.queryJobConfigById(jobId);
    	
		try {
			qrtzService.deleteJob(jobConfig);
			jobConfigService.delJobConfig(jobId);
		} catch (Exception exception) {
			exception.printStackTrace();
			mv.setViewName("redirect:/cronJob/list?page=" + page + "&error=" + URLEncoder.encode(exception.getMessage(), "UTF-8"));
			return mv;
		}
		
		mv.setViewName("redirect:/cronJob/list?page=" + page + "&msg=" + URLEncoder.encode("删除成功！", "UTF-8"));
    	
		return mv;
	}
    
	@RequiresPermissions("计划任务:启停计划任务")
    @RequestMapping(value = "/forceStop", method = RequestMethod.POST)
    @ResponseBody
	public String forceStop(int jobId) {
		JobLog jobLog = jobLogService.selectJobEntityLogById(jobId);
		
		if(jobLog == null){
			return "未找到对应的log记录！";
		}
		
		boolean foundThread = false;
		for(java.util.concurrent.ExecutorService eService : ETLExecutorService.getExecutorServices()){
        	if(!eService.isTerminated() && eService.toString().equals(jobLog.getExecutorThread())){
        		foundThread = true;
        		eService.shutdownNow(); // TODO API并不能保证立即结束
        	}
        }
		
		if (foundThread) {
			return "success";
		} else {
			return "未发现对应线程！";
		}
	}
	
	@RequiresPermissions("计划任务:启停计划任务")
    @RequestMapping(value = "/forceStopAll", method = RequestMethod.GET)
	public ModelAndView forceStopAll() {
		
		ModelAndView mv = new ModelAndView("redirect:/log/list/1");
    	setNavigateBar(mv);
		
		for(java.util.concurrent.ExecutorService eService : ETLExecutorService.getExecutorServices()){
        	if(!eService.isTerminated()){
        		eService.shutdownNow();
        	}
        }
		
		return mv;
	}
}
